import 'dart:async';
import 'dart:io';

import 'package:flutter/services.dart';

import '../loadingdialog_plugin.dart';

///@date:  2021/5/13 13:48
///@author:  lixu
///@description: native 加载框
///专为网络请求需要显示加载框的场景设计（其它场景不建议使用）
class LoadingDialogPlugin {
  static const MethodChannel _channel = const MethodChannel('flutter_nativedialog_plugin');

  ///显示原生加载框
  static const String _showHttpLoading = "showHttpLoading";
  static const String _showLoading = "showLoading";

  ///隐藏原生加载框
  static const String _hideHttpLoading = "hideHttpLoading";
  static const String _hideLoading = "hideLoading";

  ///物理返回按钮关闭弹窗事件
  ///native传递到flutter的事件
  static const String _backButtonCloseDialogEvent = "backButtonCloseDialogEvent";

  static bool _isInit = false;

  static bool _isAndroid = Platform.isAndroid;

  ///通过物理返回按钮关闭弹窗时回调
  static Map<String, Function(String tag)> _onCancelListenerMap = {};

  ///loading默认样式
  static LoadingStyle defStyle = LoadingStyle.Circle;

  static void _init() {
    if (!_isInit && _isAndroid) {
      _channel.setMethodCallHandler((handler) async {
        ///flutter收到native发送的消息
        String methodName = handler.method;
        if (_backButtonCloseDialogEvent == methodName) {
          ///物理返回按钮关闭弹窗事件
          String tag = handler.arguments;
          _onCancelListenerMap.remove(tag)?.call(tag);
        }
      });
    }
    _isInit = true;
  }

  ///http请求开始，显示native加载框
  ///[tag] 当前dialog对应的标示，当调用hideLoading()时，根据tag找到对应的dialog关闭，确保每次showLoading的tag不一样
  ///       简单来说，一个http请求对应唯一的tag，一个tag对应一个dialog
  ///[msg] 加载消息
  ///[canCancel] 能否通过返回按钮关闭
  ///[style] loading样式
  ///[onCancelListener] 当canCancel为true时，通过物理返回按钮关闭弹窗时回调onCancelListener（仅canCancel=true时，onCancelListener才有用）
  static Future showHttpLoading(
    String tag, {
    String? msg,
    bool canCancel = false,
    LoadingStyle? style,
    Function(String tag)? onCancelListener,
  }) async {
    if (_isAndroid) {
      _init();
      var map = {
        'tag': tag,
        'msg': msg,
        'canCancel': canCancel,
        'style': enumToString(style ?? defStyle) ?? 'ThreeBounce',
      };
      if (onCancelListener != null) {
        _onCancelListenerMap[tag] = onCancelListener;
      }
      return await _channel.invokeMethod(_showHttpLoading, map);
    }
  }

  ///http请求完成，隐藏native加载框
  ///[tag] 根据tag找到对应的dialog关闭
  static Future hideHttpLoading(String tag) async {
    if (_isAndroid) {
      var map = {
        'tag': tag,
      };
      _onCancelListenerMap.remove(tag);
      return await _channel.invokeMethod(_hideHttpLoading, map);
    }
  }

  ///显示native加载框（通用场景）
  ///当前方法，native公用同一个单例dialog，不管该方法调用多少次，始终显示的一个同dialog，调用hideLoading()会隐藏
  ///[msg] 加载消息
  ///[canCancel] 能否通过返回按钮关闭
  ///[style] loading样式
  static Future showLoading({String? msg, bool canCancel = false, LoadingStyle? style}) async {
    if (_isAndroid) {
      _init();
      var map = {
        'msg': msg,
        'canCancel': canCancel,
        'style': enumToString(style ?? defStyle) ?? 'ThreeBounce',
      };
      return await _channel.invokeMethod(_showLoading, map);
    }
  }

  ///隐藏native加载框，对应showLoading()方法
  static Future hideLoading() async {
    if (_isAndroid) {
      return await _channel.invokeMethod(_hideLoading);
    }
  }
}
